<template>
  <view class="component-container">
    <view @click="clickTarget" id="targetBox">
      <slot :item="currentItem" :isExpand="isShowList"></slot>
    </view>
    <view class="list" v-show="isShowList">
      <view class="list-item" v-for="(item, index) in listData" :key="index" @click="clickItem(item)">
        <image :src="item.iconImage" class="iconImage" />
        <span>{{ item.label }}</span>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { onMounted, ref, getCurrentInstance, computed, watch } from 'vue'
interface ListItem {
  label: string
  value: number
  iconImage?: string
}
const props = defineProps({
  value: {
    type: Number,
    default: undefined
  },
  width: {
    type: String,
    default: 'auto'
  },
  listData: {
    type: Object as () => Array<ListItem>,
    default: [] as Array<ListItem>
  },
  relativeLeftOffset: {
    type: Number,
    default: 0
  },
  relativeTopOffset: {
    type: Number,
    default: 0
  },
  listPadding: {
    type: String,
    default: '8px'
  },
  fontSize: {
    type: String,
    default: '27rpx'
  }
})
const emits = defineEmits<{
  (e: 'change', newVal: number): void
}>()
const pointHeight = 10
// 获取样式大小单位
function getStyleUnit(value: string): string {
  const unitMatch = value.match(/[a-zA-Z%]+/)
  return unitMatch ? unitMatch[0] : ''
}
// === vars-begin ===
const offsetTop = ref<string>('0px')
const offsetLeft = ref<string>('0px')
const halfListWidth = ref<string>('0px')

const pointHeightBandUnit = computed(() => pointHeight + 'px')
const negativePointHeightBandUnit = computed(() => -pointHeight + 'px')
const itemIconImageMarginRight = computed(() => parseFloat(props.fontSize) / 2 + getStyleUnit(props.fontSize))
// === vars-end ===
const isShowList = ref(false)
const instance = getCurrentInstance()
onMounted(() => {
  let query = uni.createSelectorQuery().in(instance)
  query
    .select('#targetBox')
    .fields({ scrollOffset: true, size: true, dataset: true, rect: true, id: true }, (res: any) => {
      offsetTop.value = res.top + res.height + props.relativeTopOffset + pointHeight + 'px'
      offsetLeft.value = res.left + props.relativeLeftOffset + 'px'
      halfListWidth.value = res.width / 2 - props.relativeLeftOffset + 'px'
    })
    .exec()
})
// 点击了指定元素域
function clickTarget() {
  isShowList.value = !isShowList.value
}
// 点击了item
const currentItem = computed(() => props.listData.find((item) => item.value === props.value))
function clickItem({ value }: ListItem) {
  console.log('内部点击', value)
  emits('change', value)
  isShowList.value = false
}
</script>

<style scoped lang="scss">
.component-container {
  z-index: 1000;

  .list::before {
    position: absolute;
    top: v-bind(negativePointHeightBandUnit);
    left: v-bind(halfListWidth);
    z-index: 100;
    display: block;
    width: 0;
    height: 0;
    border-right: v-bind(pointHeightBandUnit) solid transparent;
    border-bottom: v-bind(pointHeightBandUnit) solid #fff;
    border-left: v-bind(pointHeightBandUnit) solid transparent;
    content: '';
  }

  .list {
    position: fixed;
    top: v-bind(offsetTop);
    left: v-bind(offsetLeft);
    padding: v-bind(listPadding);
    width: v-bind(width);
    border-radius: v-bind(listPadding);
    background-color: #fff;
    box-shadow: 0 0 10px rgb(0 0 0 / 50%);
    box-sizing: border-box;

    .list-item:last-child {
      padding-bottom: 0 !important;
    }

    .list-item {
      display: flex;
      align-items: center;
      padding-bottom: 6rpx;
      font-size: v-bind(fontSize);

      .iconImage {
        margin-right: v-bind(itemIconImageMarginRight);
        width: v-bind(fontSize);
        height: v-bind(fontSize);
      }
    }
  }
}
</style>
